/**
 * @class 星空形象实体
 * @author DuskyHuang 圣子
*/

import { _decorator, Component, MeshRenderer, Vec3, Quat } from 'cc';
import { core, Notifications, utils } from 'cfw';
import { ConstGroup, DEG_PER_HOUR, Res, SceneGraph } from 'const';
import { attenuate, calcTiling, equator2ecliptic, hour2cartesian } from 'algorithms';
import { ConstStarsProxy, constStars, ui, UIProxy } from 'proxies';
import { CelestialLabel } from '../ui/items/celestial-label';
import { setLabelStyle } from 'helpers';
import { Task, TaskNames } from 'notifications';
const { ccclass } = _decorator;

@ccclass('cocosmos.CultureQuad')
export class CultureQuad extends Component {

    public loadConfig(config: constellationConfig, nearest: lightyear): this {
        this._config = config;
        const { name, center, culture: { scale, angle, offset, tex }, group, area } = this._config;
        this.node.name = name;
        const dist = nearest;
        const size = dist * scale;
        let [ra, dec] = center;
        if (notEmptyArr(offset)) {
            ra -= (offset[0] / DEG_PER_HOUR);
            dec += offset[1];
        }
        equator2ecliptic(v3a, hour2cartesian(ra, dec, dist, v3a));
        this.node.setWorldScale(size, size, 1);
        this.node.setWorldPosition(v3a);
        this.node.forward = v3a;
        this._main = group === ConstGroup.ZODIAC || area > FontSize.CONST_SML_AREA_VALUE;
        if (isNum(angle)) {
            // const { x, y, z } = this.node.eulerAngles;
            // this.node.setRotationFromEuler(x, y, z + angle);
            /**
             * TO ADJUST THIS (RECOVER DO THE OPPOSITE):
             * CLOSE: gizmos-proxy.struct&scope
             * OPEN: const-star-proxy._show_const_cults&lines&star_names
             * APPOINT: stellar-gould-belt.group&only
             * APPOINT: cosmos-proxy.INIT_POW=0
            */
            this.node.rotate(Quat.fromAngleZ(quat, angle));
        }
        if (tex) {
            const [polar, channel, span, idx] = tex.split('-');
            this._uvArr = calcTiling(+idx, +span, CULTURE_CELL_NUM);
            this._texId[0] = polar === 'N' ? 0 : 255;
            this._chArr[0] = channel === 'R' ? 255 : 0;
            this._chArr[1] = channel === 'G' ? 255 : 0;
            this._chArr[2] = channel === 'B' ? 255 : 0;
        }
        return this;
    }

    private _syncInstancing(): void {
        if (!this.node.activeInHierarchy) return;
        this._chArr[3] = constStars.cultureStrengthen * 255;
        this._mesh.setInstancedAttribute('instanced_uv', this._uvArr);
        this._mesh.setInstancedAttribute('instanced_channels', this._chArr);
        this._mesh.setInstancedAttribute('instanced_texid', this._texId);
    }

    private _syncActivating(): void {
        if (!this.node.parent || !this.node.parent.activeInHierarchy) return;
        if (!constStars.showConstCults) {
            this.node.active = false;
        } else {
            const dist = Vec3.distance(this.node.worldPosition, Vec3.ZERO);
            if (this.node.active && (dist <= Min)) {
                this.node.active = false;
            } else if (!this.node.active && (dist > Min)) {
                this.node.active = true;
            }
        }
    }

    protected onTick(dt?: time.sec, tick?: num.int): void {
        this._syncActivating();
        this._syncInstancing();
        this._syncNameLabel();
    }

    private _syncNameLabel(): void {
        const lenSqr = Vec3.squaredDistance(this.node.worldPosition, Vec3.ZERO);
        const show = ui.showConstNames && (lenSqr > 2);
        if (!show) {
            if (this._label) {
                this._label.free();
                this._label = null;
            }
        } else {
            const { name, cname } = this._config;
            if (!this._label) {
                this._label = setLabelStyle(CelestialLabel.claim('const', name), 'const', this._main);
                this._label.camera = utils.findCamera(COSMOS, DEEP);
                this._label.target = this.node;
                // this._label.string = ui.language === 'cn' ? cname : name;
                this._label.config = { en: name, cn: cname };
            }
            this._attenuateLabel(lenSqr);
        }
    }

    private _attenuateLabel(lenSqr: number): void {
        if (!this._label) return;
        // const lenSqr = Vec3.squaredDistance(this.node.worldPosition, Vec3.ZERO);
        this._label.alpha = attenuate(lenSqr, [2, 4.2], true);
    }

    protected onLoad(): void {
        this._mesh = this.getComponent(MeshRenderer);
        core.on(Notifications.Time.TICK, this.onTick, this);
    }

    protected start(): void {
        if (!CultureQuad.LoadTexTaskLaunched) {
            CultureQuad.LoadTexTaskLaunched = true;
            core.notify(Task.Load.DYNAMIC_TEX, TaskNames.TEX_CONST_NORTH);
            core.notify(Task.Load.DYNAMIC_TEX, TaskNames.TEX_CONST_SOUTH);
        }
    }

    public static LoadTexTaskLaunched: boolean = false;

    private _config: constellationConfig;
    private _label: CelestialLabel = null;
    private _mesh: MeshRenderer;
    private _uvArr: vec4<number> = [255, 255, 0, 0];
    private _chArr: vec4<number> = [0, 0, 0, 255];
    private _texId: number[] = [0];
    private _main: boolean = false;
}

const v3a = new Vec3;
const quat = new Quat;
const { CultureAtt: [Min,] } = ConstStarsProxy;
const { CULTURE_CELL_NUM } = Res.Sheets;
const { NameLabelAtt, FontSize } = UIProxy;
const { COSMOS, Cameras: { DEEP } } = SceneGraph;